using System;
using Rainbow.ObjectFlow.Framework;
using Rainbow.ObjectFlow.Interfaces;
using Rainbow.ObjectFlow.Language;

namespace Rainbow.ObjectFlow.Engine
{
    /// <summary>
    /// Joins operations for concurrent execution
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class AndOperand<T> : IAnd<T> where T : class
    {
        private readonly IWorkflow<T> _parent;
        private readonly ParallelSplitBuilder<T> _builder;

        internal TaskList<T> Tasklist;

        public AndOperand()
        {
            Tasklist = new TaskList<T>();

            _builder = new ParallelSplitBuilder<T>();
        }

        internal AndOperand(WorkflowBuilder<T> parallelSplitBuilder)
            : this()
        {
            _builder = parallelSplitBuilder as ParallelSplitBuilder<T>;
        }

        internal AndOperand(Workflow<T> workflow, WorkflowBuilder<T> parallelSplitBuilder)
            : this(parallelSplitBuilder)
        {
            _parent = workflow;
        }

        public IMerge<T> Then()
        {
            // _builder.Then();
            if (null != _parent)
                _parent.Then();

            return _parent as IMerge<T>;
        }

        public IAnd<T> Do(IOperation<T> operation)
        {
            _builder.AddOperation(operation);
            return this;
        }

        public IAnd<T> Do(Func<T, T> function)
        {
            _builder.AddOperation(function);
            return this;
        }

        public IAnd<T> Do(Func<T, T> function, ICheckConstraint constraint)
        {
            _builder.AddOperation(function, constraint);
            return this;
        }

        public IAnd<T> Do(IOperation<T> operation, ICheckConstraint constraint)
        {
            _builder.AddOperation(operation, constraint);
            return this;
        }

        public IAnd<T> Do(IWorkflow<T> workflow)
        {
            _builder.AddOperation(workflow);
            return this;
        }

        public IAnd<T> Do(IWorkflow<T> workflow, ICheckConstraint constraint)
        {
            _builder.AddOperation(workflow, constraint);
            return this;
        }

        public IAnd<T> Do<TOperation>() where TOperation : BasicOperation<T>
        {
            _builder.AddOperation<TOperation>();
            return this;
        }

        public IAnd<T> Do<TOperation>(ICheckConstraint constraint) where TOperation : BasicOperation<T>
        {
            _builder.AddOperation<TOperation>(constraint);
            return this;
        }

        public IAnd<T> And { get { return this; } set { } }

        internal void Do(OperationDuplex<T> operationDuplex)
        {
            _builder.AddOperation(operationDuplex);
        }
    }
}